package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"io/fs"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"

	_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gcfg"
	"github.com/gogf/gf/v2/os/gfile"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/sagoo-cloud/sagooiot/internal/dao"
	"github.com/sagoo-cloud/sagooiot/internal/model/entity"
)

var h bool
var m = flag.String("m", "", "菜单id,英文逗号分割")
var ctx = context.Background()

func main() {

	g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetFileName("../../manifest/config/config.yaml")
	g.DB().SetDebug(false)
	flag.Usage = usage
	flag.Parse()
	if h {
		flag.Usage()
	}

	if m == nil || len(*m) == 0 {
		g.Log().Error(ctx, errors.New("请填写参数m"))
		return
	}

	arr := strings.Split(*m, ",")
	str := ""

	for _, v := range arr {
		id, err := strconv.Atoi(v)
		if err != nil {
			panic(err)
		}

		menuIds := findChildren(id)
		for _, vv := range menuIds {
			str += createMenu(vv)
		}

	}
	path, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	path = filepath.Join(path, "./tools/gen_menu_sql/menu.sql")

	file, err := gfile.Create(path)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	defer file.Close()
	err = file.Chmod(fs.ModePerm)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	_, err = file.WriteString(str)
	if err != nil {
		g.Log().Error(ctx, err)
		return
	}
	fmt.Println("genereate success !!!")
}

func findChildren(menuId int) []int {
	sql := `with recursive tmp as (

		SELECT sys_menu.id from sys_menu  where id = ? 
		union
		select child.id from sys_menu child join tmp on tmp.id = child.parent_id
		
		)
		
		SELECT * from tmp `
	type param struct {
		Id int
	}
	all := []param{}
	err := g.DB().Ctx(context.Background()).Raw(sql, menuId).Scan(&all)
	if err != nil {
		panic(err)
	}
	allInt := []int{}
	for _, v := range all {
		allInt = append(allInt, v.Id)
	}
	return allInt
}

func createMenu(menuId int) string {

	m := menu(menuId)
	a := api(menuId)
	b := button(menuId)
	c := column(menuId)

	str := ""
	if len(m) > 0 {
		str += m + "\n"
	}
	if len(a) > 0 {
		str += a + "\n"
	}
	if len(b) > 0 {
		str += b + "\n"
	}
	if len(c) > 0 {
		str += c + "\n"
	}
	return str
}

func menu(menuId int) string {
	menu := entity.SysMenu{}
	total, err := dao.SysMenu.Ctx(context.Background()).Where(dao.SysMenu.Columns().Id, menuId).Count()
	if err != nil {
		g.Log().Error(ctx, err)
		return ""
	}
	if total == 0 {
		return ""
	}
	err = dao.SysMenu.Ctx(context.Background()).Where(dao.SysMenu.Columns().Id, menuId).Scan(&menu)
	if err != nil {
		g.Log().Error(ctx, err)
		return ""
	}
	sql := "insert into " + dao.SysMenu.Table() + " values (%s) ;  \n"
	sql = fmt.Sprintf(sql, trans(menu))
	return sql
}
func api(menuId int) string {

	total, err := dao.SysMenuApi.Ctx(context.Background()).Where(dao.SysMenuApi.Columns().Id, menuId).Count()
	if err != nil {
		g.Log().Error(ctx, err)
		return ""
	}
	if total == 0 {
		return ""
	}

	api := []entity.SysMenuApi{}
	err = dao.SysMenuApi.Ctx(context.Background()).Where(dao.SysMenuApi.Columns().MenuId, menuId).Scan(&api)
	if err != nil {
		g.Log().Error(ctx, err)
		return ""
	}
	if len(api) == 0 {
		return ""
	}
	strSplice := []string{}
	for _, v := range api {
		strSplice = append(strSplice, trans(v))
	}

	return format(strSplice, dao.SysMenuApi.Table())

}

func format(sp []string, table string) (s string) {

	sql := "insert into " + table + " values (%s) ;\n"
	for _, v := range sp {
		s += fmt.Sprintf(sql, v)
	}
	return s
}

func button(menuId int) string {

	total, err := dao.SysMenuButton.Ctx(context.Background()).Where(dao.SysMenuButton.Columns().Id, menuId).Count()
	if err != nil {
		g.Log().Error(ctx, err)
		return ""
	}
	if total == 0 {
		return ""
	}

	btn := []entity.SysMenuButton{}
	err = dao.SysMenuButton.Ctx(context.Background()).Where(dao.SysMenuButton.Columns().MenuId, menuId).Scan(&btn)
	if err != nil {
		g.Log().Error(ctx, err)
		return ""
	}
	if len(btn) == 0 {
		return ""
	}
	strSplice := []string{}
	for _, v := range btn {
		strSplice = append(strSplice, trans(v))
	}
	return format(strSplice, dao.SysMenuButton.Table())
}
func column(menuId int) string {

	total, err := dao.SysMenuColumn.Ctx(context.Background()).Where(dao.SysMenuColumn.Columns().Id, menuId).Count()
	if err != nil {
		g.Log().Error(ctx, err)
		return ""
	}
	if total == 0 {
		return ""
	}

	col := []entity.SysMenuColumn{}
	err = dao.SysMenuColumn.Ctx(context.Background()).Where(dao.SysMenuColumn.Columns().MenuId, menuId).Scan(&col)
	if err != nil {
		g.Log().Error(ctx, err)
		return ""
	}
	if len(col) == 0 {
		return ""
	}
	strSplice := []string{}
	for _, v := range col {
		strSplice = append(strSplice, trans(v))
	}
	return format(strSplice, dao.SysMenuColumn.Table())
}
func trans(target interface{}) string {
	sVal := reflect.ValueOf(target)
	sType := reflect.TypeOf(target)
	num := sVal.NumField()
	str := ""
	for i := 0; i < num; i++ {
		f := sType.Field(i)
		val := sVal.Field(i).Interface()
		if f.Name == "DeletedAt" {
			str += " null  , "
		} else {
			str += "'" + gconv.String(val) + "'" + " , "
		}

	}
	return str[:len(str)-2]
}
func usage() {
	fmt.Fprintf(os.Stderr, `Example go run main.go -m 1
Example go run main.go -m 1,2,3
`)
	flag.PrintDefaults()
}
